<!DOCTYPE html>
<title>TextEdit demo in CanvasKit</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://unpkg.com/canvaskit-wasm@0.34.1/bin/full/canvaskit.js"></script>
<script type="text/javascript" src="textapi_utils.js"></script>
<script type="text/javascript" src="spiralshader.js"></script>

<style>
canvas {
  border: 1px dashed grey;
}
</style>

<body>
  <h1>TextEdit in CanvasKit</h1>

  <canvas id=para2 width=600 height=600 tabindex='-1'></canvas>
</body>

<script type="text/javascript" charset="utf-8">
    let CanvasKit;
    onload = async () => {
      CanvasKit = await CanvasKitInit({ locateFile: (file) => 'https://unpkg.com/canvaskit-wasm@0.34.1/bin/full/'+file });
      ParagraphAPI2();
    };

    function ParagraphAPI2() {
      const surface = CanvasKit.MakeCanvasSurface('para2');
      if (!surface) {
        console.error('Could not make surface');
        return;
      }

      const mouse = MakeMouse();
      const cursor = MakeCursor(CanvasKit);
      const canvas = surface.getCanvas();
      const spiralEffect = MakeSpiralShaderEffect(CanvasKit);

      const text0 = "In a hole in the ground there lived a hobbit. Not a nasty, dirty, " +
                    "wet hole full of worms and oozy smells. This was a hobbit-hole and " +
                    "that means good food, a warm hearth, and all the comforts of home.";
      const LOC_X = 20,
            LOC_Y = 20;

      const bgPaint = new CanvasKit.Paint();
      bgPaint.setColor([0.965, 0.965, 0.965, 1]);

      const editor = MakeEditor(text0, {typeface:null, size:30}, cursor, 540);

      editor.applyStyleToRange({size:130}, 0, 1);
      editor.applyStyleToRange({italic:true}, 38, 38+6);
      editor.applyStyleToRange({color:[1,0,0,1]}, 5, 5+4);

      editor.setXY(LOC_X, LOC_Y);

      function drawFrame(canvas) {
        const lines = editor.getLines();

        canvas.clear(CanvasKit.WHITE);

        if (mouse.isActive()) {
            const pos = mouse.getPos(-LOC_X, -LOC_Y);
            const a = lines_pos_to_index(lines, pos[0], pos[1]);
            const b = lines_pos_to_index(lines, pos[2], pos[3]);
            if (a === b) {
                editor.setIndex(a);
            } else {
                editor.setIndices(a, b);
            }
        }

        canvas.drawRect(editor.bounds(), bgPaint);

        {
            // update our animated shaders
            const rad_scale = Math.sin(Date.now() / 5000) / 2;
            const shader0 = spiralEffect.makeShader([
                rad_scale,
                editor.width()/2, editor.width()/2,
                1,0,0,1,                            // color0
                0,0,1,1                             // color1
             ]);
            editor.draw(canvas, [shader0]);
            shader0.delete();
        }

        surface.requestAnimationFrame(drawFrame);
      }
      surface.requestAnimationFrame(drawFrame);

      function interact(e) {
        const type = e.type;
        if (type === 'pointerup') {
            mouse.setUp(e.offsetX, e.offsetY);
        } else if (type === 'pointermove') {
            mouse.setMove(e.offsetX, e.offsetY);
        } else if (type === 'pointerdown') {
            mouse.setDown(e.offsetX, e.offsetY);
        }
      };

      function keyhandler(e) {
          switch (e.key) {
              case 'ArrowLeft':  editor.moveDX(-1); return;
              case 'ArrowRight': editor.moveDX(1); return;
              case 'ArrowUp':
                e.preventDefault();
                editor.moveDY(-1);
                return;
              case 'ArrowDown':
                e.preventDefault();
                editor.moveDY(1);
                return;
            case 'Backspace':
                editor.deleteSelection(-1);
                return;
            case 'Delete':
                editor.deleteSelection(1);
                return;
              case 'Shift':
                return;
              case 'Tab':   // todo: figure out how to handle...
                e.preventDefault();
                return;
            }
            if (e.ctrlKey) {
                e.preventDefault();
                e.stopImmediatePropagation();
                switch (e.key) {
                    case 'r': editor.applyStyleToSelection({color:[1,0,0,1]}); return;
                    case 'g': editor.applyStyleToSelection({color:[0,0.6,0,1]}); return;
                    case 'u': editor.applyStyleToSelection({color:[0,0,1,1]}); return;
                    case 'k': editor.applyStyleToSelection({color:[0,0,0,1]}); return;

                    case 's': editor.applyStyleToSelection({shaderIndex:0}); return;

                    case 'i': editor.applyStyleToSelection({italic:'toggle'}); return;
                    case 'b': editor.applyStyleToSelection({bold:'toggle'}); return;
                    case 'w': editor.applyStyleToSelection({wavy:'toggle'}); return;

                    case ']': editor.applyStyleToSelection({size_add:1});  return;
                    case '[': editor.applyStyleToSelection({size_add:-1}); return;
                    case '}': editor.applyStyleToSelection({size_add:10});  return;
                    case '{': editor.applyStyleToSelection({size_add:-10}); return;
                }
            }
            if (!e.ctrlKey && !e.metaKey) {
                if (e.key.length == 1) {  // avoid keys like "Escape" for now
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    editor.insert(e.key);
                }
            }
      }

      document.getElementById('para2').addEventListener('pointermove', interact);
      document.getElementById('para2').addEventListener('pointerdown', interact);
      document.getElementById('para2').addEventListener('pointerup', interact);
      document.getElementById('para2').addEventListener('keydown', keyhandler);
      return surface;
    }

</script>
